home *** CD-ROM | disk | FTP | other *** search
Java Source | 1997-02-27 | 7.1 KB | 211 lines | [TEXT/CWIE] |
- /* SK8 © 1997 Apple Computer, Inc.
- This code is protected under the current SK8 License
- See http://sk8.research.apple.com/ for more information
- Apple Research Laboratories
- */
-
-
- /********************************************************************
- *
- * text, part of the SK8 collection protocol
- *
- * text would be just a wrapper around the java class StringBuffer,
- * but it's not since StringBuffer does not support removing of characters,
- * which the SK8 collection protocol requires.
- *
- * Here's how text deals with removing characters: a text
- * keeps track of the index of characters that have been removed, and then
- * skips over these characters when the caller requests an opperation on chars
- * at a particular index (from the wrapped StringBuffer).
- * From time to time, the StringBuffer is recreated without
- * the dead characters.
- *
- **********************************************************************/
-
- public abstract class text extends collection {
- // private data members
- private StringBuffer mStringBuffer;
- private final int cMaxDeadCharRuns = 40;
- private final int cDeadCharIndex = 0; //for array access
- private final int cDeadCharRunLength = 1; //for array access
- private final int cNullIndex = -1;
-
- private int[][] mDeadChars;
-
-
- /**
- ** Constructors
- **/
- public text(StringBuffer inString){
- mStringBuffer = inString;
- mDeadChars = new int[cMaxDeadCharRuns][2];
- for (int i = 0; i < cMaxDeadCharRuns; i++)
- mDeadChars[i][cDeadCharIndex] = cNullIndex;
- }
-
- public text(String inString){
- mStringBuffer = new StringBuffer(inString);
- mDeadChars = new int[cMaxDeadCharRuns][2];
- for (int i = 0; i < cMaxDeadCharRuns; i++)
- mDeadChars[i][cDeadCharIndex] = cNullIndex;;
- }
-
- public String toString(){
- refreshBuffer();
- return new String(mStringBuffer);
- }
-
- protected int stringLength() {
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
-
- int len = mStringBuffer.length();
- for(int i = 0; (i < cMaxDeadCharRuns) && (mDeadChars[i][cDeadCharIndex] != cNullIndex); i++){
- len -= mDeadChars[i][cDeadCharRunLength];
- }
- return len;
- }
-
- protected char getNthChar(int inIndex) {
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
- return mStringBuffer.charAt(ApparentIndexToActual(inIndex));
- }
-
- protected void setNthChar(int inIndex, char inCh) {
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
- mStringBuffer.setCharAt(ApparentIndexToActual(inIndex), inCh);
- }
-
- protected void insertCharacter(int inIndex, char inCh) {
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
-
- int i = ApparentIndexToActual(inIndex);
- mStringBuffer.insert(i, 1);
- mStringBuffer.setCharAt(i, inCh);
- }
-
- protected void getChars(int inStart, int inEnd, char[] inDest, int inDestBegin) {
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
-
- refreshBuffer();
- mStringBuffer.getChars(inStart, inEnd, inDest, inDestBegin);
- }
-
-
- protected void insertString(int inIndex, String inStr) {
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
-
- refreshBuffer();
- mStringBuffer.insert(inIndex, inStr);
- }
-
- protected void removeChars(int inStart, int inEnd) {
- // if the list of deadChars is full, then refresh everything
- if (mDeadChars[cMaxDeadCharRuns - 1][cDeadCharIndex] != cNullIndex)
- refreshBuffer();
-
- int actualIndex = ApparentIndexToActual(inStart);
- int numDying = inEnd - inStart;
-
- // find block before which the new block will go
- int blockAfter = 0;
- for (blockAfter = 0; blockAfter < cMaxDeadCharRuns; blockAfter++){
- if((mDeadChars[blockAfter][cDeadCharIndex] == cNullIndex) ||
- (mDeadChars[blockAfter][cDeadCharIndex] > actualIndex)){
- break;
- }
- }
-
- if ((mDeadChars[blockAfter][cDeadCharIndex] != cNullIndex) &&
- (mDeadChars[blockAfter][cDeadCharIndex] > actualIndex) &&
- (numDying + actualIndex >= mDeadChars[blockAfter][cDeadCharIndex])){
- //adjust the next block, instead of adding a new one
- int oldIndex = mDeadChars[blockAfter][cDeadCharIndex];
- mDeadChars[blockAfter][cDeadCharIndex] = actualIndex;
- mDeadChars[blockAfter][cDeadCharRunLength] += (oldIndex - actualIndex);
- int numStillToDie = numDying - (oldIndex - actualIndex);
- if (numStillToDie > 0)
- removeChars(inStart, inStart + numStillToDie);
- } else {
- //dont havt to deal with next block
- for (int i = cMaxDeadCharRuns - 2; i > blockAfter; i--){
- if (mDeadChars[i][cDeadCharIndex] != cNullIndex){
- mDeadChars[i + 1][cDeadCharIndex] = mDeadChars[i][cDeadCharIndex];
- mDeadChars[i + 1][cDeadCharRunLength] = mDeadChars[i][cDeadCharRunLength];
- }
- }
- // now blockAfter is our new target
- mDeadChars[blockAfter][cDeadCharIndex] = actualIndex;
- mDeadChars[blockAfter][cDeadCharRunLength] = numDying;
- }
- }
-
- /*
- * private stuff, dealing with dead characters
- */
-
- private void refreshBuffer(){
- if (mDeadChars[0][cDeadCharIndex] != cNullIndex) { //only do the work if we have to
-
- StringBuffer newbie = new StringBuffer();
- int endOfLastRun = 0;
-
- int tempBufferSize= 0;
- int endOfOKRun;
- int beginOfOKRun = 0;
- for(int i = 0; (i < cMaxDeadCharRuns); i++){
- if (mDeadChars[i][cDeadCharIndex] == cNullIndex){
- endOfOKRun = mStringBuffer.length();
- } else {
- endOfOKRun = mDeadChars[i][cDeadCharIndex];
- }
- if (tempBufferSize < (endOfOKRun - beginOfOKRun))
- tempBufferSize = endOfOKRun - beginOfOKRun;
-
- //set up for next time through this loop
- if (mDeadChars[i][cDeadCharIndex] != cNullIndex)
- beginOfOKRun = mDeadChars[i][cDeadCharIndex] + mDeadChars[i][cDeadCharRunLength];
- else
- break;
- }
- char[] tempBuffer = new char[tempBufferSize];
-
-
- for(int i = 0; (i < cMaxDeadCharRuns) && (mDeadChars[i][cDeadCharIndex] != cNullIndex); i++){
- mStringBuffer.getChars(endOfLastRun, mDeadChars[i][cDeadCharIndex], tempBuffer, 0);
- newbie.append(tempBuffer, 0, (mDeadChars[i][cDeadCharIndex] - endOfLastRun));
- endOfLastRun = mDeadChars[i][cDeadCharIndex] + mDeadChars[i][cDeadCharRunLength];
- //clean out the list
- mDeadChars[i][cDeadCharIndex] = cNullIndex;
- }
- //now, the last bit...
- if (endOfLastRun < mStringBuffer.length()){
- mStringBuffer.getChars(endOfLastRun, mStringBuffer.length(), tempBuffer, 0);
- newbie.append(tempBuffer, 0, (mStringBuffer.length() - endOfLastRun));
- }
- mStringBuffer = newbie;
- }
- }
-
- private int ApparentIndexToActual(int inApparent) {
- // in which we count the dead chars before the char we care about
- if (mStringBuffer == null)
- throw new RuntimeException("text not properly initialized");
-
- int deadChars = 0;
- int OKChars = 0;
- for (int i = 0; ((i < cMaxDeadCharRuns) &&
- (mDeadChars[i][cDeadCharIndex] != cNullIndex)) ; i++) {
- OKChars = (mDeadChars[i][cDeadCharIndex] - deadChars);
- if (OKChars > inApparent) //it's > not >= cuz both indices start at zero
- break;
- deadChars += mDeadChars[i][cDeadCharRunLength];
- }
- return inApparent + deadChars;
- }
- }